#include "Dual_Link_List.h"
#include "stdlib.h"

struct _ListNode {
	struct _ListNode* next;
	struct _ListNode* prior;
	void* data;
};

//Get the Node with specific index;
//Return: return the pointer to this node. If the index is illegal or the node cannot be found, NULL will be returned.
p_ListNode get_node(p_ListNode list, int index) {
	if((index<0) || (index>get_length(list)-1)) {
		printf("The index is illegal!\n");
		return NULL;
	}

	p_ListNode p = list->next;
	if(p == list) {
		printf("This is the empty list, cannot get the node!\n");
		return NULL;
	}
	int count = 0;
	while((count < index) && (p != list)) {
		p = p->next;
		count++;
	}
	if(p != list) {
		return p;
	}
	else {
		printf("cannot find the node in this list\n");		
		return NULL;
	}
}

// Get the Node with specific index, 
// Return:If the element can be found, it will return SUCCESS, or it will return FAILURE.
Status get_element(p_ListNode list, int index, void* data) {
	p_ListNode p = get_node(list,index);
	if(!p) {
		return FAILURE;
	}
	else {
		data = p->data;
		return SUCCESS;
	}
}

// get the length of link list;
// Return: length of link list.
int get_length(p_ListNode list) {
	p_ListNode p = list->next;
	int length = 0;
	while(p != list){
		p = p->next;
		length++;
	}
	return length;
}

// insert a node with a given element into a link list before a specific index
// Return: return SUCEESS if success to insert node, or it will return FAILURE.
Status insert_node(p_ListNode list, int index, void* data) {
	if((index < 0) || (index > get_length(list))) {
		printf("the laction is illegal!\n");
		return FAILURE;	
	}

	p_ListNode p =(p_ListNode)malloc(sizeof(ListNode));
	if(!p) {
		return FAILURE;
	}
	p->data = data;
	p->next = NULL;
	p->prior = NULL;

	p_ListNode q = NULL;
	if(index == get_length(list)) {
		q = list;
	}
	else {
		q = get_node(list,index);
		if(!q) {
			return FAILURE;
		}
	}

	q->prior->next = p;
	p->prior = q->prior;
	p->next = q;
	q->prior = p;

	return SUCCESS;
}

// delete a node from a link list with a specific index, the element of this deleted node will be return by para e.
// Return: return SUCCESS if delete successfully, or return FAILURE.
Status delete_node(p_ListNode list, int index, void* data) {
	if((index < 0) || (index > get_length(list)-1)) {
		return FAILURE;		
	}

	p_ListNode p = get_node(list,index);

	data = p->data;
	p_ListNode q = p->next;
	p->prior->next = q;
	q->prior = p->prior;

	free(p);

	return SUCCESS;
}

// create a link list by reading data from a given file;
// Return the neck node of created list if success to create it, or NULL will be returned. 
p_ListNode create_link_list(char* file_name) {
	FILE* pFile;
	pFile = fopen(file_name,"r");
	if(!pFile){
		printf("Fail to open file!\n");
		return NULL;
	}

	p_ListNode list = (p_ListNode)malloc(sizeof(ListNode));
	if(!list) {
		printf("The neck node is allocated failure!");
		return NULL;
	}
	list->next = list;
	list->prior = list;

	char char_read_from_file = fgetc(pFile);
	while(char_read_from_file != EOF) {
		if(insert_node(list,get_length(list),(void*)atoi(&char_read_from_file)) == FAILURE) {
			printf("Fail to creat list.\n");
			return NULL;
		}
		char_read_from_file = fgetc(pFile);
	}

	return list;
}

// Destroy the link list
// Return: void
void destroy_link_list(p_ListNode list) {
	p_ListNode p = list->next;
	p_ListNode q = NULL;
	while(p != list) {
		q = p->next;
		p->prior->next = q;
		q->prior = p->prior;
		free(p);
		p = q;
	}
	free(list);
	printf("The link list has been destroyed!\n");
}

// print all of nodes in link list sequencely to the screen
// Return: void
void print_list(p_ListNode list, ListDataPrintFunc print_data) {
	p_ListNode p = list->next;
	if(p == list) {
		printf("The list is empty!\n");
	}
	else {
		printf("The list is: \n");
		while(p != list) {
			print_data(p->data);
			p = p->next;
		}
	}
}

void print_char(void* data) {
	printf("%c", (char)data);
}


void print_int(void* data) {
	printf("%d", (int)data);
}

